package com.thinkingcoder.tcrpc.core.util;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.ClassUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TypeUtils {

    // 课程代码
    public static Object cast(Object origin, Class<?> type) {
        if (origin == null) {
            return null;
        }

        Class<?> aClass = origin.getClass();
        // 数据的类型 和 目标类型一致，则直接返回
        if (type.isAssignableFrom(aClass)) {
            return origin;
        }

        if (type.isArray()) {
            if (origin instanceof List list) {
                origin = list.toArray();
            }
            int length = Array.getLength(origin);
            Class<?> componentType = type.getComponentType();
            Object resultArray = Array.newInstance(componentType, length);
            for (int i = 0; i < length; i++) {
                if (componentType.isPrimitive() || componentType.getPackageName().startsWith("java")) {
                    // 是基本数据类型
                    Array.set(resultArray, i, Array.get(origin, i));
                } else {
                    Object castObject = cast(Array.get(origin, i), componentType);
                    Array.set(resultArray, i, castObject);
                }
            }

            return resultArray;
        }

        if (origin instanceof HashMap map) {
            JSONObject jsonObject = new JSONObject(map);
            return jsonObject.toJavaObject(type);
        }

        if (origin instanceof JSONObject jsonObject) {
            return jsonObject.toJavaObject(type);
        }

        if (type.equals(Integer.class) || type.equals(Integer.TYPE)) {
            return Integer.valueOf(origin.toString());
        } else if (type.equals(Long.class) || type.equals(Long.TYPE)) {
            return Long.valueOf(origin.toString());
        } else if (type.equals(Float.class) || type.equals(Float.TYPE)) {
            return Float.valueOf(origin.toString());
        } else if (type.equals(Double.class) || type.equals(Double.TYPE)) {
            return Double.valueOf(origin.toString());
        } else if (type.equals(Byte.class) || type.equals(Byte.TYPE)) {
            return Byte.valueOf(origin.toString());
        } else if (type.equals(Short.class) || type.equals(Short.TYPE)) {
            return Short.valueOf(origin.toString());
        } else if (type.equals(Character.class) || type.equals(Character.TYPE)) {
            return Character.valueOf(origin.toString().charAt(0));
        } else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE)) {
            return Boolean.valueOf(origin.toString());
        }

        return null;
    }

    public static Object castMethodResult(Method method, Object data) {
        Class<?> type = method.getReturnType();
        log.debug("method.getReturnType() = " + type);
        if (data instanceof JSONObject jsonResult) {
            if (Map.class.isAssignableFrom(type)) {
                Map resultMap = new HashMap();
                Type genericReturnType = method.getGenericReturnType();
                log.debug(genericReturnType.toString());
                if (genericReturnType instanceof ParameterizedType parameterizedType) {
                    Class<?> keyType = (Class<?>)parameterizedType.getActualTypeArguments()[0];
                    Class<?> valueType = (Class<?>)parameterizedType.getActualTypeArguments()[1];
                    log.debug("keyType  : " + keyType);
                    log.debug("valueType: " + valueType);
                    jsonResult.entrySet().stream().forEach(e -> {
                        Object key = cast(e.getKey(), keyType);
                        Object value = cast(e.getValue(), valueType);
                        resultMap.put(key, value);
                    });
                }
                return resultMap;
            }
            return jsonResult.toJavaObject(type);
        } else if (data instanceof JSONArray jsonArray) {
            Object[] array = jsonArray.toArray();
            if (type.isArray()) {
                Class<?> componentType = type.getComponentType();
                Object resultArray = Array.newInstance(componentType, array.length);
                for (int i = 0; i < array.length; i++) {
                    if (componentType.isPrimitive() || componentType.getPackageName().startsWith("java")) {
                        Array.set(resultArray, i, array[i]);
                    } else {
                        Object castObject = cast(array[i], componentType);
                        Array.set(resultArray, i, castObject);
                    }
                }
                return resultArray;
            } else if (List.class.isAssignableFrom(type)) {
                List<Object> resultList = new ArrayList<>(array.length);
                Type genericReturnType = method.getGenericReturnType();
                log.debug(genericReturnType.toString());
                if (genericReturnType instanceof ParameterizedType parameterizedType) {
                    Type actualType = parameterizedType.getActualTypeArguments()[0];
                    log.debug(actualType.toString());
                    for (Object o : array) {
                        resultList.add(cast(o, (Class<?>)actualType));
                    }
                } else {
                    resultList.addAll(Arrays.asList(array));
                }
                return resultList;
            } else {
                return null;
            }
        } else {
            return cast(data, type);
        }
    }

    // 自己优化后
    public static Object cast(Object sourceObj, Class<?> targetClz, Type genericType) {
        // 判断源对象是否为空
        if (sourceObj == null) {
            return null;
        }

        if (String.class.isAssignableFrom(targetClz)) {
            return String.valueOf(sourceObj);
        }

        // 判断 目标数据类型 是否 为 基本数据类型 或 其包装类
        if (ClassUtils.isPrimitiveOrWrapper(targetClz)) {
            return castBaseType(sourceObj, targetClz);
        }
        // 处理 目标类型 为 数组 的
        else if (targetClz.isArray()) {
            if (sourceObj instanceof List list) {
                sourceObj = list.toArray();
            }
            int len = Array.getLength(sourceObj);
            Class<?> componentType = targetClz.getComponentType();
            Object resultArray = Array.newInstance(componentType, len);
            for (int i = 0; i < len; i++) {
                Array.set(resultArray, i, cast(Array.get(sourceObj, i), componentType, genericType));
            }
            return resultArray;
        }
        // 处理 目标类型 为 List子集 的
        else if (List.class.isAssignableFrom(targetClz)) {
            List<Object> resultList = null;
            if (sourceObj instanceof List list) {
                resultList = new ArrayList<>(list.size());
                if (genericType instanceof ParameterizedType parameterizedType) {
                    Class<?> actualType = (Class<?>)parameterizedType.getActualTypeArguments()[0];
                    for (int i = 0; i < list.size(); i++) {
                        resultList.add(cast(list.get(i), actualType, genericType));
                    }
                }

            }
            return resultList;
        }
        // 处理 目标类型 为 Map子集 的
        else if (Map.class.isAssignableFrom(targetClz)) {
            Map resultMap = new HashMap();
            if (sourceObj instanceof Map map) {

                if (genericType instanceof ParameterizedType parameterizedType) {
                    Class<?> keyType = (Class<?>)parameterizedType.getActualTypeArguments()[0];
                    Class<?> valueType = (Class<?>)parameterizedType.getActualTypeArguments()[1];
                    map.entrySet().stream().forEach(entryTemp -> {
                        Object key = cast(((Map.Entry)entryTemp).getKey(), keyType, genericType);
                        Object value = cast(((Map.Entry)entryTemp).getValue(), valueType, genericType);
                        resultMap.put(key, value);
                    });
                }
            }
            return resultMap;
        }
        // 处理 目标类型 为 其他 的
        else {
            // 如果 源数据 类型为 Map子集 的
            if (sourceObj instanceof Map map) {
                JSONObject jsonObject = new JSONObject(map);
                return jsonObject.toJavaObject(targetClz);
            }

        }

        return null;
    }

    /**
     * 处理 8 种 基本数据类型or包装类
     * 
     * @param sourceObj 源数据对象
     * @param targetClz 目标类
     * @return 转换后的目标数据对象
     */
    private static Object castBaseType(Object sourceObj, Class<?> targetClz) {
        if (targetClz.equals(Integer.class) || targetClz.equals(Integer.TYPE)) {
            return Integer.valueOf(sourceObj.toString());
        } else if (targetClz.equals(Long.class) || targetClz.equals(Long.TYPE)) {
            return Long.valueOf(sourceObj.toString());
        } else if (targetClz.equals(Float.class) || targetClz.equals(Float.TYPE)) {
            return Float.valueOf(sourceObj.toString());
        } else if (targetClz.equals(Double.class) || targetClz.equals(Double.TYPE)) {
            return Double.valueOf(sourceObj.toString());
        } else if (targetClz.equals(Byte.class) || targetClz.equals(Byte.TYPE)) {
            return Byte.valueOf(sourceObj.toString());
        } else if (targetClz.equals(Short.class) || targetClz.equals(Short.TYPE)) {
            return Short.valueOf(sourceObj.toString());
        } else if (targetClz.equals(Character.class) || targetClz.equals(Character.TYPE)) {
            return sourceObj.toString().charAt(0);
        } else if (targetClz.equals(Boolean.class) || targetClz.equals(Boolean.TYPE)) {
            return Boolean.valueOf(sourceObj.toString());
        }
        return null;
    }
}
